# -*- coding: utf-8 -*-

"""
# @Time    : 2021/6/14 18:20
# @User  : Mabin
# @Descriotion  :OSS相关
"""
import os
import oss2
import requests
import time
from application.constant import OSS_TIME_OUT, ALL_OSS, CURRENT_PROTOCOL, CONFIG_PUBLIC_INTERFACE

# 阿里云OSS标识映射
OSS_MAPPING = {
    # 线上
    "medpeer-translate": "trans",
    "medpeer-article": "article",
    "medpeer-image": "image",
    "medpeer-technique": "technique",
    "medpeer-temporary": "temporary",
    # 测试服
    "medmdt-fanyi-test": "trans",
    "medmdt-article-test": "article",
    "medmdt-image-test": "image",
    "medmdt-test": "technique",
}


class BaseOss:
    cache_config = dict()

    def __init__(self, bucket_sign=None, bucket_name=None, instance_type=1):
        """
        初始化OSS实例
        :author Mabin
        :param str bucket_sign:bucket标识，
            trans（medpeer-translate）
            article（medpeer-article）
            image（medpeer-image）
            technique（medpeer-technique）
            默认article
        :param str bucket_name:bucket名称(仅通过{'bucket_name': '', 'file_path': ''}读取文件时使用)
        :param int instance_type:实例类型，1为外网实例，2为内网实例，3为海外加速实例
        """
        # 若传入了bucket_name，则覆盖bucket_sign相关信息
        if bucket_name:
            bucket_sign = OSS_MAPPING[bucket_name]

        # 设置相关参数（存储了实际的bucket_name）
        self.bucket_name = self.get_system_config(self.get_bucket_info(bucket_sign))

        if instance_type == 1:
            # 初始化外网实例
            self._oss_model = self._init_out_oss_client(bucket_sign)
        elif instance_type == 2:
            # 初始化内网实例
            self._oss_model = self._init_intranet_oss_client(bucket_sign)
        elif instance_type == 3:
            # 初始化海外加速实例
            self._oss_model = self._init_accelerate_oss_client(bucket_sign)
        else:
            # 默认初始化外网实例
            self._oss_model = self._init_out_oss_client(bucket_sign)

    def generate_file_url(self, oss_path):
        """
        获取OSS文件访问链接
        :author:Mabin
        :param str oss_path:OSS目标文件路径
        :return:
        """
        if not oss_path or str(oss_path).lower() == "none":
            return {"result": False, "msg": "传入数据为空！", "data": None}

        signed_url = self._oss_model.sign_url("GET", oss_path, OSS_TIME_OUT)

        # 替换访问地址
        # bucket = self.get_system_config(self.get_bucket_info(self._bucket_sign))
        # show_bucket = self.get_system_config(self._get_show_bucket(self._bucket_sign))
        # endpoint = self.get_system_config(ALL_OSS["outsideEndpoint"])
        # show_endpoint = self.get_system_config(ALL_OSS["outsideEndpointShow"])
        # signed_url = str(signed_url).replace(bucket, show_bucket)
        # signed_url = signed_url.replace(endpoint, show_endpoint)

        return {"result": True, "msg": "ok！", "data": signed_url}

    def upload_file_object(self, local_file, oss_path):
        """
        上传本地文件至OSS
        :author:Mabin
        :param str local_file:本地文件路径
        :param str oss_path:OSS存储路径
        :return:
        """
        if not os.path.exists(local_file):
            return {"result": False, "msg": "请确认本地文件是否存在！" + local_file}

        self._oss_model.put_object_from_file(oss_path, local_file)

        return {"result": True, "msg": "文件上传成功！"}

    def download_file_object(self, download_local, oss_path):
        """
        下载文件至本地
        :author:Mabin
        :param str download_local:本地文件存储位置
        :param str oss_path:OSS目标文件路径
        :return:
        """
        # 判断文件目录是否存在
        file_path, temp_name = os.path.split(download_local)
        if not os.path.exists(file_path) and file_path:
            # 目录不存在 则创建
            os.makedirs(file_path)

        try:
            self._oss_model.get_object_to_file(oss_path, download_local)
        except Exception as e:
            return {"result": False, "msg": str(e)}

        return {"result": True, "msg": "OSS文件下载成功！"}

    @staticmethod
    def generate_oss_path(local_file, target_type=2, **extra_param):
        """
        生成OSS文件上传路径
        :author:Mabin
        :param str local_file:本地文件路径
        :param any target_type:文件类别，用于区分不同业务的文件：
            1为基金报告渲染图片相关文件，
            2为国自然申请书用户上传模板相关，
            "lnf_application"为地方自然申请书用户上传模板相关，
        :param any extra_param:额外参数
        :return:
        """
        if not local_file:
            return {"result": False, "msg": "传入数据为空！"}

        # 获取本地文件名称
        filepath, temp_filename = os.path.split(local_file)

        # 根据类型组织OSS路径
        if target_type == 1:
            # 基金报告渲染图片相关文件
            oss_path = f"science_foundation/generate_report/{time.strftime('%Y')}/{temp_filename}"
        elif target_type == 2:
            # 国自然申请书用户上传模板
            oss_path = f"science_foundation/ai_writer/{time.strftime('%Y')}/{temp_filename}"
        elif target_type == "lnf_application":
            # 地方自然申请书用户上传模板
            oss_path = f"science_foundation/ai_writer/{time.strftime('%Y')}/{temp_filename}"
        else:
            return {"result": False, "msg": "请确认本地文件是否存在！"}

        return {"result": True, "msg": "ok！", "data": oss_path}

    def _init_out_oss_client(self, bucket_sign):
        """
        初始化client,外网
        :author:Mabin
        :param str bucket_sign:bucket标识
        :return:
        :rtype oss2.Bucket
        """
        access_key_id = self.get_system_config(ALL_OSS['accessKeyId'])
        access_key_secret = self.get_system_config(ALL_OSS['accessKeySecret'])
        endpoint = self.get_system_config(ALL_OSS['outsideEndpoint'])
        bucket = self.get_system_config(self.get_bucket_info(bucket_sign))
        # show_bucket = self.get_system_config(self._get_show_bucket(self._bucket_sign))
        # show_endpoint = self.get_system_config(ALL_OSS["outsideEndpointShow"])

        # 根据CURRENT_PROTOCOL调整htpps或http
        # cname = f"{CURRENT_PROTOCOL}{show_bucket}.{show_endpoint}"
        # bucket_model = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), cname, bucket, is_cname=True)
        bucket_model = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket)

        return bucket_model

    def _init_intranet_oss_client(self, bucket_sign):
        """
        初始化client,内网
        :author:Mabin
        :param str bucket_sign:bucket标识
        :return:
        :rtype oss2.Bucket
        """
        access_key_id = self.get_system_config(ALL_OSS['accessKeyId'])
        access_key_secret = self.get_system_config(ALL_OSS['accessKeySecret'])
        endpoint = self.get_system_config(ALL_OSS['insideEndpoint'])
        bucket = self.get_system_config(self.get_bucket_info(bucket_sign))

        # 创建客户端
        bucket_model = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket)

        return bucket_model

    def _init_accelerate_oss_client(self, bucket_sign):
        """
        初始化client,海外加速
        :author:Mabin
        :param str bucket_sign:bucket标识
        :return:
        """
        access_key_id = self.get_system_config(ALL_OSS['accessKeyId'])
        access_key_secret = self.get_system_config(ALL_OSS['accessKeySecret'])
        endpoint = "oss-accelerate.aliyuncs.com"  # 海外加速使用
        bucket = self.get_system_config(self.get_bucket_info(bucket_sign))

        # 创建客户端
        bucket_model = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket)

        return bucket_model

    @staticmethod
    def get_bucket_info(bucket_sign):
        """
        获取bucket配置
        :author:Mabin
        :param str bucket_sign:bucket标识
        :return:
        """
        bucket_sign = str(bucket_sign).lower()
        bucket_list = {
            "trans": ALL_OSS["translateBucket"],
            "article": ALL_OSS["articleBucket"],
            "image": ALL_OSS["imageBucket"],
            "technique": ALL_OSS["techniqueBucket"],
        }
        return bucket_list[bucket_sign] if bucket_sign in bucket_list else ALL_OSS["articleBucket"]

    @staticmethod
    def _get_show_bucket(bucket_sign):
        """
        获取bucket展示替换配置
        :author:Mabin
        :param str bucket_sign:bucket标识
        :return:
        """
        bucket_sign = str(bucket_sign).lower()
        bucket_list = {
            "trans": ALL_OSS["translateBucketShow"],
            "article": ALL_OSS["articleBucketShow"],
            "image": ALL_OSS["imageBucketShow"],
            "technique": ALL_OSS["techniqueBucketShow"],
        }
        return bucket_list[bucket_sign] if bucket_sign in bucket_list else ALL_OSS["techniqueBucketShow"]

    @classmethod
    def get_system_config(cls, config_name):
        """
        获取系统配置
        :author: Mabin
        :param str config_name:配置标识
        :return:
        """
        if config_name in cls.cache_config:
            # 存在记录
            return cls.cache_config[config_name]

        # 不存在记录，则查询相关数据
        result = requests.post(
            CONFIG_PUBLIC_INTERFACE, data={"name": config_name}, verify=False
        )
        result = result.json()

        if not result["result"]:
            # 查询失败
            return None

        # 查询成功，则记录相关数据
        cls.cache_config[config_name] = result["msg"]
        return result["msg"]
